#include "NetworkHandler.h"

#include "ScreenHandler.h"
#include "WorldHandler.h"
#include "Logging.h"
#include "NetworkPacket.h"
#include "Config.h"

#include <sstream>

#ifdef _WIN32
	#include <windows.h>
#else
	#include <unistd.h>
#endif

#define TIMEOUT_MAX 5

NetworkHandler* globalCSHandler;

NetworkHandler::NetworkHandler()
{
	hasConnection = false;
	delay = 35;
}

void NetworkHandler::setDelay(unsigned int passedDelay)
{
	delay = passedDelay;
}

void NetworkHandler::threadLoop()
{
	USLEEP(35);
	for(unsigned int i = 1; /*!stopRequested*/ ; ++i)
	{
		if(delay <= i)
		{			
			if(hasConnection == true)
			{
				prepareSendQueue();
			}
			
			sendMessages();
			clearSendQueue();
			
			i = 1;
		}
		else
		{
			USLEEP(1);
		}
	}
}

bool NetworkHandler::interruptWait()
{
//	waitInterrupted = true;
	thread->interrupt();
	return true;
}

void NetworkHandler::start()
{
	std::string localPlayerName = globalConfig.getLocalPlayerName();

    thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&NetworkHandler::threadLoop, this)));

    socketCommunicator.start();
}

void NetworkHandler::stop()
{
//	stopRequested = true;

    socketCommunicator.stop();

    int n = static_cast<int>(boost::posix_time::time_duration::ticks_per_second()) / 10;
    boost::posix_time::time_duration delay(0, 0, 0, n); //linus boostvalds
    
	thread->timed_join(delay);
}

void NetworkHandler::clearSendQueue()
{
	sendQueue.clear();
}

void NetworkHandler::addToSendQueue(uintptr_t pointer, HeaderType headerType)
{
	switch(headerType)
	{
		case INIT:
		case DISC:
		case SHUTDOWN:
		case CHATMESSAGE:
		case CHATLOG:
		case GRANTSEEDANDTP:
		case REQUESTSEEDANDTP:
		case GRANTDISMANTLE:
		case REQUESTDISMANTLE:
		case REQUESTRESS:
		case ACTIVATECOMPASS:
		case INACTIVATECOMPASS:
			sendQueue.push_back(std::make_pair(headerType, *reinterpret_cast<std::string*>(pointer))); //no serialization
		break;
		case PLAYEROBJECT:
		case PLAYEROBJECTVECTOR:
		case PACKETBUNDLE:
		case ATTACKOBJECT:
		case ATTACKOBJECTVECTOR:
		case ENEMYOBJECT:
		case ENEMYOBJECTVECTOR:
			sendQueue.push_back(std::make_pair(headerType, serializer.callSerialize(pointer, headerType))); //serialize
		break;
		default:
			std::cout << "CASE " << headerType << " NOT HANDLED IN NetworkHandler::addToSendQueue()\n";
			assert(" " == 0);
		break;
	}

}

void NetworkHandler::addToReceivedQueue(const std::string& serializedData, ClientAddress* clientAddress)
{
	std::vector<NetworkPacket> newPackets;
	
	if(serializer.callDeserialize(reinterpret_cast<uintptr_t>(&newPackets), PACKETBUNDLE, serializedData) == true)
	{
		ClientAddress dClientAddress = *clientAddress;

		size_t i;
		for(i = 0; i < newPackets.size(); ++i)
		{
			receivedQueue.push_back(std::make_pair<NetworkPacket, ClientAddress>(newPackets.at(i), dClientAddress));
		}
	}
}

bool NetworkHandler::getHasConnection()
{
	return hasConnection;
}

void NetworkHandler::setHasConnection(bool passedHasConnection)
{
	hasConnection = passedHasConnection;
}

PlayerObject* NetworkHandler::getPlayerObjectFromName(const std::string& name)
{
	std::map<std::string, PlayerObject*>::iterator it = clientPlayerObjectMap.find(name);
	if(it != clientPlayerObjectMap.end())
	{
		return static_cast<PlayerObject*>(it->second);
	}
	else
	{
		return NULL;
	}
}
#if 0


if(globalWorldHandler.getPlayerCount() > 0)
{	
	NetworkPacket pobjPacket;

 	std::vector<PlayerObject*>playerObjects = globalWorldHandler.getPlayerObjects();
    PlayerObject playerObject = *playerObjects[globalWorldHandler.getLocalPlayerIndex()];

    
	pobjPacket.push_back(std::make_pair(POBJ, serializer.callSerialize(reinterpret_cast<uintptr_t>(&playerObject), PLAYEROBJECT)));
    sendSync(serializer.callSerialize(reinterpret_cast<uintptr_t>(&pobjPacket), NETWORKPACKET));
}
#endif
